https://kubernetes.io/docs/concepts/workloads/pods/disruptions/#pod-disruption-conditions
若要建立一個高可用的 APP,則需要更加認識在 pods 可能會發生的各種干擾類型
pods 不會自己消失,除非有人特別銷毀,或者出現了不可避免的硬體或軟體錯誤,
非自願干擾有以下情況:
以上處了資源不足以外,都不是僅特定於 k8s 平台上的問題,比較會是 nodes 本身的問題
自願干擾則包括 APP 所有者與集群管理者發起的操作, APP 所有者的操作包括有以下:
集群管理者做的以下動作也是:
日常使用中最常遇到出現干擾問題的,應該就是當要升級 cluster 時,做的 drain node 動作就會觸發 pdb (底下會討論到)
如果設定了 pdb,但是因為 drain Node 導致該 pods 無法符合 pdb 的話,drain node 動作就會永遠卡死 (若沒有設定 timeout 的話),因此在安排升級 k8s cluster 版本時,可以特別注意一下
另外也不是所有的自願干擾都會觸發 pbd,比如主動的 delete pods 動作並不會因為 pdb 的關係被擋住。
要避免非自願干擾影響到 cluster,可以做以下調整:
在一個基本的 k8s cluster 中,不會有自願干擾 (只會有 user 觸發的干擾),若是使用雲端託管的 k8s cluster,通常會有文件可以參考有哪些自願干擾會發生,而最常見會觸發自願干擾的行為有:
當某個 APP 希望能夠保持一定數量的可用狀態時,可以配置 PodDisruptionBudget
(PDB),來確保此 APP 的 pods 不會少於一定數量
比如當某 APP 的配置為 .spec.replicas: 5
的話,代表 deployment 會建立 5 個 pods。如果配置 pdb 允許最少必須要有 3 個副本的話,當 Eviction API 觸發時 (通常是 drain node 觸發的),最多就是同時 2 的 pods 自願干擾 (也就是刪除並排到新的 nodes 上)
不過當 Deployment 進行 rolling update 時不受到 pdb 的限制,APP 更新期間的可用故障管理是在對應的 workload 資源定義的
pdb 可以設定兩種 “不健康的 pod 驅逐策略” (k8s 1.31 stable),官方建議設定 AlwaysAllow
,差異為:
筆者目前不大確定這兩者的差異,或許明天再嘗試實作看看會更清楚~
另外筆者也是第一次注意到有 Eviction API 的存在,此 API 可以指定某 pods 觸發 Eviction API,或許比起直接 delete pods 觸發重建 pods 更為優雅一些。
官方文件這邊的例子蠻清楚的,礙於篇幅就不逐條解釋了,我認為的幾個重點:
而影響干擾的速度有以下變因:
算是比較新的功能,會 pods 上面描述被干擾的原因,會寫在 reason 的欄位,有以下幾種:
PreemptionByScheduler
:因為有更高優先權的 pods 建立,因此 scheduler
觸發的搶占資源情況DeletionByTaintManager
:由 kube-controller-manager
觸發,主要當 nodes 被打上了 NoExecute
的 taints 導致某 pods 無法再執行EvictionByEvictionAPI
:pods 被標記為 eviction (透過 k8s API)DeletionByPodGC
:當 pods 已經不被某 nodes 綁定,會由 Pod garbage collection 觸發TerminationByKubelet
:由 kubelet 觸發,可能是因為 node pressure 驅除 (最常見於 disk 空間不足),或是 graceful node shutdown,又或是有系統重要的 pods 造成的搶占。筆者在看這段時,發現一個有趣的現象 (與此主題無關)
就是英文版的文件是寫此功能為 1.31 (stable)
而簡體中文版的文件是寫此功能為 1.26 (beta)
看來又是可以發 PR 說我有在 kubernetes 貢獻的經驗了 (誤
當我們要針對 k8s cluster 內的所有 node 進行升級 (k8s or 系統本身的升級),可以規劃以下內容:
https://kubernetes.io/docs/concepts/scheduling-eviction/api-eviction/
上面有提到除了 drain node 之外,我們也可以透過 Eviction API 來主動觸發驅逐,就來試試看吧~
可以透過程式語言內的 SDK 呼叫,另外也可以直接使用 curl 指令來帶入資料觸發
先建立一個 pods,在 default ns
中且叫做 eviction-pods
:
❯ kubectl run eviction-pods --image=nginx
要使用 curl 的話,要先寫好一個 policy 檔案:
# eviction.json
{
"apiVersion": "policy/v1",
"kind": "Eviction",
"metadata": {
"name": "eviction-pods",
"namespace": "default"
}
}
這邊我們直接使用 apiserver 的憑證來測試 (因為需要 root 權限才能讀 key, 因此使用 sudo),並帶入 policy:
sudo curl -k -H 'Content-type: application/json' --cacert /etc/kubernetes/pki/ca.crt \
--key /etc/kubernetes/pki/apiserver-kubelet-client.key \
--cert /etc/kubernetes/pki/apiserver-kubelet-client.crt \
https://192.168.75.10:6443/api/v1/namespaces/default/pods/eviction-pods/eviction -d @eviction.json
會回傳:
{
"kind": "Status",
"apiVersion": "v1",
"metadata": {},
"status": "Success",
"code": 201
}%
查看 events 不會特別看到有 evitced 的狀態,僅有被 killing 的 events 出現
❯ k events
...
74s Normal Started Pod/eviction-pods Started container eviction-pods
74s Normal Created Pod/eviction-pods Created container eviction-pods
71s Normal Killing Pod/eviction-pods Stopping container eviction-pods
...
APP 的高可用性可以說是 k8s 最主要的強項,而對於管理 cluster 的人來說,確保 node 的日常維運不會影響到 APP 使用,且進行更新時做好規劃都是很重要的議題 ~
https://kubernetes.io/docs/concepts/workloads/pods/disruptions/#pod-disruption-conditions
https://kubernetes.io/zh-cn/docs/tasks/run-application/configure-pdb/#unhealthy-pod-eviction-policy
https://kubernetes.io/docs/tasks/administer-cluster/safely-drain-node/#eviction-api
https://kubernetes.io/docs/concepts/scheduling-eviction/api-eviction/